package com.chy.summer.link.api.impl;

import com.chy.summer.link.api.RequestParameter;
import com.sun.istack.internal.Nullable;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * 请求参数的持有对象实现
 */
public class RequestParameterImpl implements RequestParameter {

    /**
     * 参数名
     */
    private String name;
    /**
     * 参数值
     */
    private Object value;

    public RequestParameterImpl(String name, Object value) {
        this.name = name;
        this.value = value;
    }

    /**
     * 将两个参数合并
     * @param mergingObj 合并过来的参数
     */
    @Override
    public RequestParameter merge(RequestParameter mergingObj) {
        if (this.isArray() && mergingObj.isArray()) {
            //如果是个列表，直接将新参数添加到原本的列表里面就行了
            mergingObj.getArray().addAll(this.getArray());
        } else if (this.isObject() && mergingObj.isObject()) {
            //map的处理
            Map<String, RequestParameter> map = new HashMap<>();
            map.putAll(((Map<String, RequestParameter>) value));
            for (String key : mergingObj.getObjectKeys()) {
                map.put(key, mergingObj.getObjectValue(key));
            }
            mergingObj.setValue(map);
        }
        return mergingObj;
    }

    public RequestParameterImpl(String name) {
        this(name, null);
    }

    public RequestParameterImpl() {
        this(null, null);
    }

    @Override
    public @Nullable
    String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setValue(Object value) {
        this.value = value;
    }

    public Object getValue() {
        return this.value;
    }

    @Override
    public @Nullable
    List<String> getObjectKeys() {
        return (isObject()) ? new ArrayList<>(((Map<String, RequestParameter>) value).keySet()) : null;
    }

    @Override
    public RequestParameter getObjectValue(String key) {
        return (isObject()) ? ((Map<String, RequestParameter>) value).get(key) : null;
    }

    @Override
    public boolean isObject() {
        return !isNull() && value instanceof Map;
    }

    @Override
    public @Nullable
    List<RequestParameter> getArray() {
        return (isArray()) ? ((List<RequestParameter>) value) : null;
    }

    @Override
    public boolean isArray() {
        return !isNull() && value instanceof List;
    }

    @Override
    public @Nullable
    String getString() {
        return (isString()) ? ((String) value) : null;
    }

    @Override
    public boolean isString() {
        return !isNull() && value instanceof String;
    }

    @Override
    public @Nullable
    Integer getInteger() {
        return (isInteger()) ? ((Integer) value) : null;
    }

    @Override
    public boolean isInteger() {
        return !isNull() && value instanceof Integer;
    }

    @Override
    public @Nullable
    Long getLong() {
        return (isLong()) ? ((Long) value) : null;
    }

    @Override
    public boolean isLong() {
        return !isNull() && value instanceof Long;
    }

    @Override
    public @Nullable
    Float getFloat() {
        return (isFloat()) ? ((Float) value) : null;
    }

    @Override
    public boolean isFloat() {
        return !isNull() && value instanceof Float;
    }

    @Override
    public @Nullable
    Double getDouble() {
        return (isDouble()) ? ((Double) value) : null;
    }

    @Override
    public boolean isDouble() {
        return !isNull() && value instanceof Double;
    }

    @Override
    public @Nullable
    Boolean getBoolean() {
        return (isBoolean()) ? ((Boolean) value) : null;
    }

    @Override
    public boolean isBoolean() {
        return !isNull() && value instanceof Boolean;
    }

    @Override
    public @Nullable
    JsonObject getJsonObject() {
        return (isJsonObject()) ? ((JsonObject) value) : null;
    }

    @Override
    public boolean isJsonObject() {
        return !isNull() && value instanceof JsonObject;
    }

    @Override
    public @Nullable
    JsonArray getJsonArray() {
        return (isJsonArray()) ? ((JsonArray) value) : null;
    }

    @Override
    public boolean isJsonArray() {
        return !isNull() && value instanceof JsonArray;
    }

    @Override
    public boolean isNull() {
        return value == null;
    }

    @Override
    public boolean isEmpty() {
        return isNull();
    }

    @Override
    public Object toJson() {
        if (isArray()) {
            return new JsonArray(getArray().stream().map(RequestParameter::toJson).collect(Collectors.toList()));
        }
        else if (isObject()) {
            return ((Map<String, RequestParameter>) value)
                    .entrySet()
                    .stream()
                    .collect(Collector.of(
                            JsonObject::new,
                            (j, e) -> j.put(e.getKey(), e.getValue().toJson()),
                            JsonObject::mergeIn
                    ));
        }
        else {
            return value;
        }
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        RequestParameterImpl that = (RequestParameterImpl) o;
        return Objects.equals(name, that.name) &&
                Objects.equals(value, that.value);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }
}